package cn.skyquant.quant4j.service.boot.web.controller;

import cn.skyquant.quant4j.api.authority.AuthorityService;
import cn.skyquant.quant4j.api.authority.UserDTO;
import cn.skyquant.quant4j.api.dto.ResultDTO;
import cn.skyquant.quant4j.api.sms.SmsService;
import cn.skyquant.quant4j.service.boot.model.authority.AppContext;
import cn.skyquant.quant4j.service.boot.model.authority.RoleAuthority;
import cn.skyquant.quant4j.service.boot.web.WebConstants;
import cn.skyquant.quant4j.service.boot.web.annotation.NoVerify;
import cn.skyquant.quant4j.service.boot.web.config.RoleMenuConfig;
import cn.skyquant.quant4j.service.boot.web.vo.MenuVO;
import cn.skyquant.quant4j.service.boot.web.vo.UserVO;
import cn.skyquant.quant4j.sdk.util.log.LogUtil;
import com.google.common.collect.Sets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Set;

@RestController
@RequestMapping("/authority")
public class AuthorityController {

    @Autowired
    AuthorityService authorityService;
    @Autowired
    SmsService smsService;
    @Autowired
    AppContext appContext;

    @Value("${server.domain}")
    String domain;
    @Value("${server.cookie.path}")
    String cookie_path;
    @Value("${server.cookie.max-age}")
    int cookie_max_age;


    private static final ResultDTO userNotExist = ResultDTO.error("用户不存在");
    private static final ResultDTO userNotLogin = ResultDTO.error("请先登录");
    private static final ResultDTO telNotMatch = ResultDTO.error("手机号不匹配");
    private static final Set<String> defaultRole = Sets.newHashSet(RoleAuthority.guest);//默认有访客权限
    private static final UserVO userVO = new UserVO("访客",null,RoleMenuConfig.getMenuByRole(defaultRole));
    private static final ResultDTO<UserVO> defaultUserVO = ResultDTO.success(userVO);

    final ResultDTO<Void> success = ResultDTO.success();

    //获取当前用户信息
    @RequestMapping(value = "",method = RequestMethod.GET)
    @ResponseBody
    @NoVerify
    public ResultDTO<UserVO> get(){
        UserDTO userDTO = appContext.get();
        if(userDTO!=null){
//            throw new RuntimeException("获取用户信息错误");
            UserVO userVO = convertUserDTOToUserVO(userDTO);
            return ResultDTO.success(userVO);
        }else {
            return defaultUserVO;
        }
    }

    //用户登录
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    @ResponseBody
    @NoVerify
    public ResultDTO<UserVO> login(
            @RequestParam(value = "tel",required = true)String tel,
            @RequestParam(value = "password",required = true)String password,
            HttpServletRequest request,
            HttpServletResponse response) {
        ResultDTO<UserDTO> resultDTO = authorityService.login(tel,password);
        if(resultDTO.okData()){
            UserDTO userDTO = resultDTO.data;
            UserVO userVO = convertUserDTOToUserVO(userDTO);
            setCookie(response,userDTO);
            LogUtil.info(String.format("%s login",userDTO.name));
            return ResultDTO.success(userVO);
        }else {
            return ResultDTO.error(resultDTO.message);
        }
    }

    //用户注销
    @RequestMapping(value = "/logout",method = RequestMethod.POST)
    @ResponseBody
    public ResultDTO<Void> logout(HttpServletResponse response) {
        UserDTO userDTO = appContext.get();
        if(userDTO!=null){
            LogUtil.info(String.format("%s logout",userDTO.name));
            deleteCookie(response,userDTO);
            return authorityService.logout(userDTO.id);
        }else {
            return userNotExist;
        }
    }

    //注册前发送手机验证码
    @RequestMapping(value = "/send_reg_sms",method = RequestMethod.POST)
    @ResponseBody
    @NoVerify
    public ResultDTO<Void> regSms(
            @RequestParam(value = "tel",required = true)String tel){
        return smsService.regCode(tel);
    }

    //注册
    @RequestMapping(value = "/reg",method = RequestMethod.POST)
    @ResponseBody
    @NoVerify
    public ResultDTO<Void> reg(
            @RequestParam(value = "tel",required = true)String tel,
            @RequestParam(value = "name",required = true)String name,
            @RequestParam(value = "code",required = true)String code,
            @RequestParam(value = "password",required = true)String password){
        //先验证手机验证码
        ResultDTO<Void> resultDTO = smsService.checkRegCode(tel,code);
        if(resultDTO.ok){
            ResultDTO<UserDTO> userDTOResult = authorityService.reg(tel,name,password);
            if(userDTOResult.ok){
                return success;
            }else{
                return ResultDTO.error(userDTOResult.message);
            }
        }
        return resultDTO;
    }

    //修改资料前发送手机验证码
    @RequestMapping(value = "/send_update_sms",method = RequestMethod.POST)
    @ResponseBody
    @NoVerify
    public ResultDTO<Void> updateSms(
            @RequestParam(value = "tel",required = true)String tel){
        return smsService.loginCode(tel);
    }

    //修改资料
    @RequestMapping(value = "",method = RequestMethod.PUT)
    @ResponseBody
    @NoVerify
    public ResultDTO<Void> update(
            @RequestParam(value = "tel",required = true)String tel,
            @RequestParam(value = "name",required = true)String name,
            @RequestParam(value = "code",required = true)String code,
            @RequestParam(value = "password",required = true)String password){
        ResultDTO<Void> checkResult = smsService.checkLoginCode(tel,code);
        //再验证手机码
        if(checkResult.ok){
            return authorityService.update(tel,name,password);
        }else {
            return checkResult;
        }
    }

    //下面是私有方法
    private void setCookie(HttpServletResponse response,UserDTO userDTO){
        Cookie[] cookies = new Cookie[3];
        cookies[0] = new Cookie(WebConstants.COOKIE_TEL,userDTO.tel);
        cookies[1] = new Cookie(WebConstants.COOKIE_TOKEN,userDTO.token);
        cookies[2] = new Cookie(WebConstants.COOKIE_LOGIN_TIME,WebConstants.format(userDTO.gmtLastLogin));
        for(Cookie cookie:cookies){
            cookie.setVersion(0);
            cookie.setMaxAge(cookie_max_age);
            cookie.setPath(cookie_path);
            cookie.setDomain(domain);
            //这两个是为了加强安全
            cookie.setHttpOnly(true);
            cookie.setSecure(true);
            response.addCookie(cookie);
        }
    }

    private void deleteCookie(HttpServletResponse response,UserDTO userDTO){
        Cookie[] cookies = new Cookie[3];
        cookies[0] = new Cookie(WebConstants.COOKIE_TEL,"");
        cookies[1] = new Cookie(WebConstants.COOKIE_TOKEN,"");
        cookies[2] = new Cookie(WebConstants.COOKIE_LOGIN_TIME,"");
        for(Cookie cookie:cookies){
            cookie.setVersion(0);
            cookie.setMaxAge(0);
            cookie.setDomain(domain);
            cookie.setPath(cookie_path);
            response.addCookie(cookie);
        }
    }

    private UserVO convertUserDTOToUserVO(UserDTO userDTO){
        Set<String> roles = userDTO.getRoles();
        List<MenuVO> menuVOS = RoleMenuConfig.getMenuByRole(roles);
        UserVO userVO = new UserVO(userDTO.name,userDTO.tel,menuVOS);
        userVO.roles = roles;
        return userVO;
    }
}
